home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / lib / python2.6 / distutils / fancy_getopt.pyc (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2009-04-20  |  12.2 KB  |  385 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyc (Python 2.6)
  3.  
  4. '''distutils.fancy_getopt
  5.  
  6. Wrapper around the standard getopt module that provides the following
  7. additional features:
  8.   * short and long options are tied together
  9.   * options have help strings, so fancy_getopt could potentially
  10.     create a complete usage summary
  11.   * options set attributes of a passed-in object
  12. '''
  13. __revision__ = '$Id: fancy_getopt.py 60923 2008-02-21 18:18:37Z guido.van.rossum $'
  14. import sys
  15. import string
  16. import re
  17. from types import *
  18. import getopt
  19. from distutils.errors import *
  20. longopt_pat = '[a-zA-Z](?:[a-zA-Z0-9-]*)'
  21. longopt_re = re.compile('^%s$' % longopt_pat)
  22. neg_alias_re = re.compile('^(%s)=!(%s)$' % (longopt_pat, longopt_pat))
  23. longopt_xlate = string.maketrans('-', '_')
  24.  
  25. class FancyGetopt:
  26.     '''Wrapper around the standard \'getopt()\' module that provides some
  27.     handy extra functionality:
  28.       * short and long options are tied together
  29.       * options have help strings, and help text can be assembled
  30.         from them
  31.       * options set attributes of a passed-in object
  32.       * boolean options can have "negative aliases" -- eg. if
  33.         --quiet is the "negative alias" of --verbose, then "--quiet"
  34.         on the command line sets \'verbose\' to false
  35.     '''
  36.     
  37.     def __init__(self, option_table = None):
  38.         self.option_table = option_table
  39.         self.option_index = { }
  40.         if self.option_table:
  41.             self._build_index()
  42.         
  43.         self.alias = { }
  44.         self.negative_alias = { }
  45.         self.short_opts = []
  46.         self.long_opts = []
  47.         self.short2long = { }
  48.         self.attr_name = { }
  49.         self.takes_arg = { }
  50.         self.option_order = []
  51.  
  52.     
  53.     def _build_index(self):
  54.         self.option_index.clear()
  55.         for option in self.option_table:
  56.             self.option_index[option[0]] = option
  57.         
  58.  
  59.     
  60.     def set_option_table(self, option_table):
  61.         self.option_table = option_table
  62.         self._build_index()
  63.  
  64.     
  65.     def add_option(self, long_option, short_option = None, help_string = None):
  66.         if long_option in self.option_index:
  67.             raise DistutilsGetoptError, "option conflict: already an option '%s'" % long_option
  68.         long_option in self.option_index
  69.         option = (long_option, short_option, help_string)
  70.         self.option_table.append(option)
  71.         self.option_index[long_option] = option
  72.  
  73.     
  74.     def has_option(self, long_option):
  75.         """Return true if the option table for this parser has an
  76.         option with long name 'long_option'."""
  77.         return long_option in self.option_index
  78.  
  79.     
  80.     def get_attr_name(self, long_option):
  81.         """Translate long option name 'long_option' to the form it
  82.         has as an attribute of some object: ie., translate hyphens
  83.         to underscores."""
  84.         return string.translate(long_option, longopt_xlate)
  85.  
  86.     
  87.     def _check_alias_dict(self, aliases, what):
  88.         if not type(aliases) is DictionaryType:
  89.             raise AssertionError
  90.         for alias, opt in aliases.items():
  91.             if alias not in self.option_index:
  92.                 raise DistutilsGetoptError, "invalid %s '%s': option '%s' not defined" % (what, alias, alias)
  93.             alias not in self.option_index
  94.             if opt not in self.option_index:
  95.                 raise DistutilsGetoptError, "invalid %s '%s': aliased option '%s' not defined" % (what, alias, opt)
  96.             opt not in self.option_index
  97.         
  98.  
  99.     
  100.     def set_aliases(self, alias):
  101.         '''Set the aliases for this option parser.'''
  102.         self._check_alias_dict(alias, 'alias')
  103.         self.alias = alias
  104.  
  105.     
  106.     def set_negative_aliases(self, negative_alias):
  107.         """Set the negative aliases for this option parser.
  108.         'negative_alias' should be a dictionary mapping option names to
  109.         option names, both the key and value must already be defined
  110.         in the option table."""
  111.         self._check_alias_dict(negative_alias, 'negative alias')
  112.         self.negative_alias = negative_alias
  113.  
  114.     
  115.     def _grok_option_table(self):
  116.         """Populate the various data structures that keep tabs on the
  117.         option table.  Called by 'getopt()' before it can do anything
  118.         worthwhile.
  119.         """
  120.         self.long_opts = []
  121.         self.short_opts = []
  122.         self.short2long.clear()
  123.         self.repeat = { }
  124.         for option in self.option_table:
  125.             if len(option) == 3:
  126.                 (long, short, help) = option
  127.                 repeat = 0
  128.             elif len(option) == 4:
  129.                 (long, short, help, repeat) = option
  130.             else:
  131.                 raise ValueError, 'invalid option tuple: %r' % (option,)
  132.             if len(option) == 3(long) is not StringType or len(long) < 2:
  133.                 raise DistutilsGetoptError, "invalid long option '%s': must be a string of length >= 2" % long
  134.             len(long) < 2
  135.             if not short is None and type(short) is StringType and len(short) == 1:
  136.                 raise DistutilsGetoptError, "invalid short option '%s': must a single character or None" % short
  137.             len(short) == 1
  138.             self.repeat[long] = repeat
  139.             self.long_opts.append(long)
  140.             if long[-1] == '=':
  141.                 if short:
  142.                     short = short + ':'
  143.                 
  144.                 long = long[0:-1]
  145.                 self.takes_arg[long] = 1
  146.             else:
  147.                 alias_to = self.negative_alias.get(long)
  148.                 if alias_to is not None:
  149.                     if self.takes_arg[alias_to]:
  150.                         raise DistutilsGetoptError, "invalid negative alias '%s': aliased option '%s' takes a value" % (long, alias_to)
  151.                     self.takes_arg[alias_to]
  152.                     self.long_opts[-1] = long
  153.                     self.takes_arg[long] = 0
  154.                 else:
  155.                     self.takes_arg[long] = 0
  156.             alias_to = self.alias.get(long)
  157.             if alias_to is not None:
  158.                 if self.takes_arg[long] != self.takes_arg[alias_to]:
  159.                     raise DistutilsGetoptError, "invalid alias '%s': inconsistent with aliased option '%s' (one of them takes a value, the other doesn't" % (long, alias_to)
  160.                 self.takes_arg[long] != self.takes_arg[alias_to]
  161.             
  162.             if not longopt_re.match(long):
  163.                 raise DistutilsGetoptError, ("invalid long option name '%s' " + '(must be letters, numbers, hyphens only') % long
  164.             longopt_re.match(long)
  165.             self.attr_name[long] = self.get_attr_name(long)
  166.             if short:
  167.                 self.short_opts.append(short)
  168.                 self.short2long[short[0]] = long
  169.                 continue
  170.         
  171.  
  172.     
  173.     def getopt(self, args = None, object = None):
  174.         """Parse command-line options in args. Store as attributes on object.
  175.  
  176.         If 'args' is None or not supplied, uses 'sys.argv[1:]'.  If
  177.         'object' is None or not supplied, creates a new OptionDummy
  178.         object, stores option values there, and returns a tuple (args,
  179.         object).  If 'object' is supplied, it is modified in place and
  180.         'getopt()' just returns 'args'; in both cases, the returned
  181.         'args' is a modified copy of the passed-in 'args' list, which
  182.         is left untouched.
  183.         """
  184.         if args is None:
  185.             args = sys.argv[1:]
  186.         
  187.         if object is None:
  188.             object = OptionDummy()
  189.             created_object = 1
  190.         else:
  191.             created_object = 0
  192.         self._grok_option_table()
  193.         short_opts = string.join(self.short_opts)
  194.         
  195.         try:
  196.             (opts, args) = getopt.getopt(args, short_opts, self.long_opts)
  197.         except getopt.error:
  198.             msg = None
  199.             raise DistutilsArgError, msg
  200.  
  201.         for opt, val in opts:
  202.             if len(opt) == 2 and opt[0] == '-':
  203.                 opt = self.short2long[opt[1]]
  204.             elif not len(opt) > 2 or opt[:2] == '--':
  205.                 raise AssertionError
  206.             opt = opt[2:]
  207.             alias = self.alias.get(opt)
  208.             if alias:
  209.                 opt = alias
  210.             
  211.             if not self.takes_arg[opt]:
  212.                 if not val == '':
  213.                     raise AssertionError, "boolean option can't have value"
  214.                 alias = self.negative_alias.get(opt)
  215.                 if alias:
  216.                     opt = alias
  217.                     val = 0
  218.                 else:
  219.                     val = 1
  220.             
  221.             attr = self.attr_name[opt]
  222.             if val and self.repeat.get(attr) is not None:
  223.                 val = getattr(object, attr, 0) + 1
  224.             
  225.             setattr(object, attr, val)
  226.             self.option_order.append((opt, val))
  227.         
  228.         if created_object:
  229.             return (args, object)
  230.         return args
  231.  
  232.     
  233.     def get_option_order(self):
  234.         """Returns the list of (option, value) tuples processed by the
  235.         previous run of 'getopt()'.  Raises RuntimeError if
  236.         'getopt()' hasn't been called yet.
  237.         """
  238.         if self.option_order is None:
  239.             raise RuntimeError, "'getopt()' hasn't been called yet"
  240.         self.option_order is None
  241.         return self.option_order
  242.  
  243.     
  244.     def generate_help(self, header = None):
  245.         '''Generate help text (a list of strings, one per suggested line of
  246.         output) from the option table for this FancyGetopt object.
  247.         '''
  248.         max_opt = 0
  249.         for option in self.option_table:
  250.             long = option[0]
  251.             short = option[1]
  252.             l = len(long)
  253.             if long[-1] == '=':
  254.                 l = l - 1
  255.             
  256.             if short is not None:
  257.                 l = l + 5
  258.             
  259.             if l > max_opt:
  260.                 max_opt = l
  261.                 continue
  262.         
  263.         opt_width = max_opt + 2 + 2 + 2
  264.         line_width = 78
  265.         text_width = line_width - opt_width
  266.         big_indent = ' ' * opt_width
  267.         if header:
  268.             lines = [
  269.                 header]
  270.         else:
  271.             lines = [
  272.                 'Option summary:']
  273.         for option in self.option_table:
  274.             (long, short, help) = option[:3]
  275.             text = wrap_text(help, text_width)
  276.             if long[-1] == '=':
  277.                 long = long[0:-1]
  278.             
  279.             if short is None:
  280.                 if text:
  281.                     lines.append('  --%-*s  %s' % (max_opt, long, text[0]))
  282.                 else:
  283.                     lines.append('  --%-*s  ' % (max_opt, long))
  284.             else:
  285.                 opt_names = '%s (-%s)' % (long, short)
  286.                 if text:
  287.                     lines.append('  --%-*s  %s' % (max_opt, opt_names, text[0]))
  288.                 else:
  289.                     lines.append('  --%-*s' % opt_names)
  290.             for l in text[1:]:
  291.                 lines.append(big_indent + l)
  292.             
  293.         
  294.         return lines
  295.  
  296.     
  297.     def print_help(self, header = None, file = None):
  298.         if file is None:
  299.             file = sys.stdout
  300.         
  301.         for line in self.generate_help(header):
  302.             file.write(line + '\n')
  303.         
  304.  
  305.  
  306.  
  307. def fancy_getopt(options, negative_opt, object, args):
  308.     parser = FancyGetopt(options)
  309.     parser.set_negative_aliases(negative_opt)
  310.     return parser.getopt(args, object)
  311.  
  312. WS_TRANS = string.maketrans(string.whitespace, ' ' * len(string.whitespace))
  313.  
  314. def wrap_text(text, width):
  315.     """wrap_text(text : string, width : int) -> [string]
  316.  
  317.     Split 'text' into multiple lines of no more than 'width' characters
  318.     each, and return the list of strings that results.
  319.     """
  320.     if text is None:
  321.         return []
  322.     if len(text) <= width:
  323.         return [
  324.             text]
  325.     text = string.expandtabs(text)
  326.     text = string.translate(text, WS_TRANS)
  327.     chunks = re.split('( +|-+)', text)
  328.     chunks = filter(None, chunks)
  329.     lines = []
  330.     while chunks:
  331.         cur_line = []
  332.         cur_len = 0
  333.         while chunks:
  334.             l = len(chunks[0])
  335.             if cur_len + l <= width:
  336.                 cur_line.append(chunks[0])
  337.                 del chunks[0]
  338.                 cur_len = cur_len + l
  339.                 continue
  340.             len(text) <= width
  341.             if cur_line and cur_line[-1][0] == ' ':
  342.                 del cur_line[-1]
  343.             
  344.             break
  345.         if chunks:
  346.             if cur_len == 0:
  347.                 cur_line.append(chunks[0][0:width])
  348.                 chunks[0] = chunks[0][width:]
  349.             
  350.             if chunks[0][0] == ' ':
  351.                 del chunks[0]
  352.             
  353.         
  354.         lines.append(string.join(cur_line, ''))
  355.     return lines
  356.  
  357.  
  358. def translate_longopt(opt):
  359.     '''Convert a long option name to a valid Python identifier by
  360.     changing "-" to "_".
  361.     '''
  362.     return string.translate(opt, longopt_xlate)
  363.  
  364.  
  365. class OptionDummy:
  366.     '''Dummy class just used as a place to hold command-line option
  367.     values as instance attributes.'''
  368.     
  369.     def __init__(self, options = []):
  370.         """Create a new OptionDummy instance.  The attributes listed in
  371.         'options' will be initialized to None."""
  372.         for opt in options:
  373.             setattr(self, opt, None)
  374.         
  375.  
  376.  
  377. if __name__ == '__main__':
  378.     text = 'Tra-la-la, supercalifragilisticexpialidocious.\nHow *do* you spell that odd word, anyways?\n(Someone ask Mary -- she\'ll know [or she\'ll\nsay, "How should I know?"].)'
  379.     for w in (10, 20, 30, 40):
  380.         print 'width: %d' % w
  381.         print string.join(wrap_text(text, w), '\n')
  382.         print 
  383.     
  384.  
  385.